#pragma once

#include <iostream>
#include <string>
#include <functional>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>
#include <pthread.h>
#include <sys/types.h>
#include <memory>
#include "InetAddr.hpp"
#include "Log.hpp"
#include <string.h>

//模板方法模式
namespace sock_ns
{
    static const int gbacklog = 8;

    class Socket;
    using socket_ptr = std::shared_ptr<Socket>;

    class Socket
    {
    public:
        //纯虚函数
        virtual void CreateSocketOrDie() = 0;
        virtual void BindSocketOrDie(InetAddr& addr) = 0;
        virtual void ListenSocketOrDie() = 0;
        virtual socket_ptr Accepter(InetAddr* addr) = 0;
        virtual bool Connector(InetAddr& addr) = 0;
        virtual int Recv(std::string* out) = 0;//输出型参数
        virtual int Send(const std::string& in) = 0;
        virtual int SockFd() = 0;



        void BuildListenSocket(InetAddr& addr)
        {
            
            CreateSocketOrDie();
            BindSocketOrDie(addr);
            ListenSocketOrDie();
            
            
        }

        bool BuildClientSocket(InetAddr& addr)
        {
            CreateSocketOrDie();
            return Connector(addr);
        }
    };


    class TcpSocket : public Socket
    {
    public:
        TcpSocket(int sockfd = -1)
        :_sockfd(sockfd)
        {}

        void CreateSocketOrDie() override
        {
            _sockfd = socket(AF_INET,SOCK_STREAM,0);
            if(_sockfd<0)
            {

                Log(FATAL,"socket error\n");
                exit(-1);
            }
            Log(DEBUG,"socket create success,sockfd:%d\n",_sockfd);

        }
        
        void BindSocketOrDie(InetAddr& addr) override
        {
            struct sockaddr_in local;
            memset(&local,0,sizeof(local));
            local.sin_family = AF_INET;
            //不管数据是从哪个网卡过来的，只要是绑定的端口号过来的数据，都可以接收到。
            local.sin_addr.s_addr = inet_addr(addr.Ip().c_str());
            local.sin_port = htons(addr.Port());
            int n = bind(_sockfd,(struct sockaddr*)&local,sizeof(local));
            if(n<0)
            {
                Log(FATAL,"bind error\n");
                exit(-2);
            }
            Log(DEBUG,"bind success,sockfd:%d\n",_sockfd);
        }

        void ListenSocketOrDie() override
        {
            int n = listen(_sockfd,gbacklog);
            if(n<0)
            {
                Log(FATAL,"listen error\n");
                exit(-3);
            }
            Log(DEBUG,"liseten success,sockfd:%d\n",_sockfd);
        }

        socket_ptr Accepter(InetAddr* addr) override
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int sockfd = accept(_sockfd,(struct sockaddr*)&peer,&len);
            if(sockfd<0)
            {
                Log(WARNING,"accept error\n");
                return nullptr;
                //如果得到的fd<0，就继续接受连接
            }
            *addr = peer;
            Log(DEBUG,"accept success,sockfd:%d\n",sockfd);
            socket_ptr sock = std::make_shared<TcpSocket>(sockfd);//想要使用多态
            return sock;
        }

        bool Connector(InetAddr& addr) override
        {

            struct sockaddr_in server;
            memset(&server,0,sizeof(server));
            server.sin_family = AF_INET;
            server.sin_port = htons(addr.Port());
            server.sin_addr.s_addr = inet_addr(addr.Ip().c_str());

            int n = connect(_sockfd,(struct sockaddr*)&server,sizeof(server));
            if(n<0)
            {
                std::cerr<<strerror(errno)<<"   "<<errno<<std::endl;
                return false;
            }
            return true;
        }

        int SockFd() override
        {
            return _sockfd;
        }

        int Recv(std::string* out) override
        {
            char buffer[1024];
            size_t n = recv(_sockfd,buffer,sizeof(buffer),0);
            if(n>0)
            {
                buffer[n] = 0;
                *out += buffer;
            }
            return n;
        }

        int Send(const std::string& out) override
        {
            int n = send(_sockfd,out.c_str(),out.size(),0);
            return n;
        }

    private:
        int _sockfd;

    };
}
